package keer.httpinterface.http;

import keer.httpinterface.HttpInterfaceException;
import keer.httpinterface.utils.StringUtils;

import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 封装Content-Type请求/响应头信息的封装类
 *
 * @author Keer
 * @since 1.0.0
 */
public class HttpContentType {
    private String charset;
    private Map<String, String> parameters;
    private final static String CHARSET_KEY = "charset";
    private final String type;
    private final String subType;

    private HttpContentType(String type, String subType, Map<String, String> parameters) {
        this.type = type;
        this.subType = subType;
        this.parameters = new LinkedHashMap<>();
        if (parameters != null) {
            this.parameters.putAll(parameters);
        }
        for (String key : this.parameters.keySet()) {
            if (CHARSET_KEY.equalsIgnoreCase(key)) {
                charset = this.parameters.get(key);
            }
        }
        if (charset == null || charset.trim().isEmpty()) {
            charset = StandardCharsets.UTF_8.name();
            this.parameters.put(CHARSET_KEY, charset);
        }
    }
    /**
     * 获取Content-Type类型
     * @return 类型
     */
    public String getType() {
        return this.type;
    }

    /**
     * 获取Content-Type子类型
     * @return 子类型
     */
    public String getSubType() {
        return subType;
    }

    /**
     * 获取Content-Type的字符集
     * @return 字符集
     */
    public String getCharset() {
        return charset;
    }

    /**
     * 获取Content-Type的参数
     * @return 参数
     */
    public Map<String, String> getParameters() {
        return Collections.unmodifiableMap(parameters);
    }

    /**
     * 设置参数
     *
     * 该方法用于向参数集合中添加或更新一个键值对参数
     * 如果给定的键已经存在于参数集合中，该方法将更新该键对应的值
     * 如果不存在，则将该键值对添加到参数集合中
     *
     * @param key 参数的键，用于唯一标识一个参数，不应为null
     * @param value 参数的值，提供与键关联的值，可以为null
     */
    public void setParameter(String key, String value) {
        parameters.put(key, value);
    }
    /**
     * 设置Content-Type的字符集
     * @param charset 字符集
     */
    public void setCharset(String charset) {
        parameters.put(CHARSET_KEY, charset);
        this.charset = charset;
    }

    /**
     * 静默的获取Content-Type，忽略构造过程中抛出的所有异常
     * @param value 待解析的Content-Type
     * @return HttpContentType
     */
    protected static HttpContentType ofQuietly(String value) {
        try {
            return of(value);
        } catch (HttpInterfaceException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 解析Content-Type,转换成{@link HttpContentType}对象
     * @param value 待解析的Content-Type
     * @return HttpContentType
     * @throws HttpInterfaceException 解析异常
     */
    public static HttpContentType of(String value) throws HttpInterfaceException  {
        if (value == null) {
            return null;
        }
        String[] arr = value.split("/");
        String type = arr[0];
        String subType = arr.length > 1 ? arr[1] : "";
        Map<String, String> parameters = null;
        if (subType.contains(";")) {
            arr = subType.split(";");
            subType = arr[0];
            if (arr.length > 1) {
                parameters = new HashMap<>();
                for (int i = 1; i < arr.length; i++) {
                    String[] kv = arr[i].split("=");
                    parameters.put(kv[0].trim(), kv.length > 1 ? kv[1].trim() : "");
                }
            }
        }
        return new HttpContentType(type, subType, parameters);
    }

    /**
     * 输出不包含参数的Content-Type字符串
     * @return String 不包含参数的Content-Type字符串
     */
    public String contentType() {
        return getType() + "/" + getSubType();
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(getType());
        sb.append("/");
        sb.append(getSubType());
        if (parameters != null && !parameters.isEmpty()) {
            sb.append("; ");
            for (String key : parameters.keySet()) {
                String v = parameters.get(key);
                if (StringUtils.isBlank(v)) {
                    continue;
                }
                sb.append(key);
                sb.append("=");
                sb.append(parameters.get(key));
                sb.append("; ");
            }
        }
       return sb.toString();
    }
}
